import { ILoadingHelper } from '@/core/interface';
import { AppMobLoading } from '@components/common/loading';
import { createVNode, render as vueRender } from 'vue';

/**
 * 加载助手
 *
 * @export
 * @class AppLoadingHelper
 * @implements {ILoadingHelper}
 */
export class AppLoadingHelper implements ILoadingHelper {
	/**
	 * 全局唯一应用加载助手实例对象
	 *
	 * @private
	 * @static
	 * @type {ILoadingHelper}
	 * @memberof AppLoadingHelper
	 */
	private static helper: ILoadingHelper;

	/**
	 * 获取应用加载助手实例对象
	 *
	 * @static
	 * @return {*}
	 * @memberof AppLoadingHelper
	 */
	public static getInstance(
		type?: 'VIEW' | 'CONTROL',
		parent?: ILoadingHelper,
		bc?: Function,
		ec?: Function
	) {
		if (!this.helper) {
			this.helper = new AppLoadingHelper(type, parent, bc, ec);
		}
		return this.helper;
	}

	/**
	 * Creates an instance of AppLoadingHelper.
	 * @param {('VIEW' | 'CONTROL')} type 加载助手类型
	 * @param {ILoadingHelper} [parent] 父级加载助手
	 * @param {Function} [bc] 开始加载回调
	 * @param {Function} [ec] 结束加载回调
	 * @memberof AppLoadingHelper
	 */
	constructor(
		private readonly type: 'VIEW' | 'CONTROL' | 'APP' = 'APP',
		private readonly parent?: ILoadingHelper,
		public bc?: Function,
		public ec?: Function
	) {}

	/**
	 * 是否加载中
	 *
	 * @type {boolean}
	 * @memberof AppLoadingHelper
	 */
	public isLoading: boolean = false;

	/**
	 * 加载状态绑定节点
	 *
	 * @private
	 * @type {(HTMLElement | null)}
	 * @memberof AppLoadingHelper
	 */
	private loadingBindElement: HTMLElement | null = null;

	/**
	 * 加载计数
	 *
	 * @private
	 * @type {number}
	 * @memberof AppLoadingHelper
	 */
	private loadingCount: number = 0;

	/**
	 * 开始加载
	 *
	 * @memberof AppLoadingHelper
	 */
	beginLoading(elementKey: string = 'app'): void {
		this.loadingCount += 1;
		if (this.isLoading) {
			return;
		}
		this.isLoading = true;
		this.createLoadingMask(elementKey);
		if (this.parent) {
			this.parent.beginLoading();
		}
		if (this.bc && this.bc instanceof Function) {
			this.bc();
		}
	}

	/**
	 * 结束加载
	 *
	 * @return {*}  {void}
	 * @memberof AppLoadingHelper
	 */
	endLoading(): void {
		if (!this.isLoading && this.loadingCount === 0) {
			return;
		}
		this.isLoading = false;
		this.loadingCount -= 1;
		this.destroyLoadingMask();
		if (this.parent) {
			this.parent.endLoading();
		}
		if (this.ec && this.ec instanceof Function) {
			this.ec();
		}
	}

	/**
	 * 创建加载遮罩
	 *
	 * @private
	 * @param {string} [elementKey]
	 * @return {*}
	 * @memberof AppLoadingHelper
	 */
	private createLoadingMask(elementKey: string) {
		let element: HTMLElement | null = null;
		try {
			element = document.getElementById(elementKey);
		} catch (error) {
			console.log(error);
		}
		if (!element) {
			return;
		}
		element.style.pointerEvents = 'none';
		this.loadingBindElement = element;
		const loadingMask = document.createElement('div');
		loadingMask.classList.add(
			'loading-mask',
			`loading-mask-${this.type.toLowerCase()}`
		);
		loadingMask.id = `loading-mask-${elementKey}`;
		const loadingMaskSpin = createVNode(AppMobLoading);
		// 注入vue上下文，修复视图独立打开加载组件失效
		const appInstance = App.getUIAppInstance();
		if (appInstance) {
			loadingMaskSpin.appContext = appInstance.appContext;
		}
		vueRender(loadingMaskSpin, loadingMask as any);
		element.appendChild(loadingMask);
	}

	/**
	 * 销毁加载遮罩
	 *
	 * @private
	 * @memberof AppLoadingHelper
	 */
	private destroyLoadingMask() {
		if (this.loadingBindElement) {
			this.loadingBindElement.style.pointerEvents = 'auto';
			const lastChild = this.loadingBindElement.lastChild as HTMLElement;
			if (
				lastChild &&
				lastChild.classList &&
				lastChild.classList.contains('loading-mask')
			) {
				lastChild.remove();
			}
		}
	}
}
